#include "Logger.h"
#include <iostream>
#include <Windows.h>
#include <QDir>

using namespace OOP;

Logger Logger::_sLogger;

Logger::Logger () : _mode (DEBUG_OUT)
{

}

Logger::~Logger ()
{
}

QString Logger::_getTimeSimpleFormat (quint8 dayTimeFlag)
{
	SYSTEMTIME wtm;
	GetLocalTime(&wtm);
	QString dayStr, timeStr;
	if (dayTimeFlag & INCLUDE_DAY) {
		dayStr = QString ("%1%2%3").arg (wtm.wYear, 4, 10, QChar('0'))
				.arg (wtm.wMonth, 2, 10, QChar('0'))
				.arg (wtm.wDay, 2, 10, QChar('0'));
	}
	if (dayTimeFlag & INCLUDE_TIME) {
		timeStr = QString ("%1%2%3").arg (wtm.wHour, 2, 10, QChar('0'))
				.arg (wtm.wMinute, 2, 10, QChar('0'))
				.arg (wtm.wSecond, 2, 10, QChar('0'));
	}
	return dayStr + timeStr;
}

QString Logger::_getTimeFullFormat (quint8 dayTimeFlag)
{
	SYSTEMTIME wtm;
	GetLocalTime(&wtm);
	QString dayStr, timeStr;
	if (dayTimeFlag & INCLUDE_DAY) {
		dayStr = QString ("%1/%2/%3").arg (wtm.wYear, 4, 10, QChar('0'))
				.arg (wtm.wMonth, 2, 10, QChar('0'))
				.arg (wtm.wDay, 2, 10, QChar('0'));
	}
	if (dayTimeFlag & INCLUDE_TIME) {
		timeStr = QString ("%1:%2:%3").arg (wtm.wHour, 2, 10, QChar('0'))
				.arg (wtm.wMinute, 2, 10, QChar('0'))
				.arg (wtm.wSecond, 2, 10, QChar('0'));
	}
	if (!dayStr.isEmpty () && !timeStr.isEmpty ())
		return dayStr + " " + timeStr;
	return dayStr + timeStr;
}

void Logger::setMode (int mode, const QString &logDir)
{
	_sLogger._setMode (mode, logDir);
}

void Logger::_setMode (int mode, const QString &logDir)
{
	_mode = mode;
	if (_mode & FILE_OUT) {
		QDir ().mkdir (logDir);
		_outLogStream.open ((logDir + "\\" + _getTimeSimpleFormat () + ".log")
				.toStdString ());
		if (!_outLogStream)
			OutputDebugStringW (L"Warning: Log file could not be opened. "
					L"Log will not be written to file\n");
	} else {
		_outLogStream.close ();
	}
}

void Logger::info (const char *funcStr, const QString &msg)
{
	_sLogger._info (funcStr, msg);
}

void Logger::warning (const char *funcStr, const QString &msg)
{
	_sLogger._warning (funcStr, msg);
}

void Logger::warning (const char *funcStr, const QString &msg,
		OOPException &e)
{
	_sLogger._warning (funcStr, msg, e);
}

void Logger::critical (const char *funcStr, const QString &msg)
{
	_sLogger._critical (funcStr, msg);
}

void Logger::critical (const char *funcStr, const QString &msg,
		OOPException &e)
{
	_sLogger._critical (funcStr, msg, e);
}

void Logger::_info (const char *funcStr, const QString &msg)
{
	QString funcQStr = (funcStr == NULL ? "Unknown" :
			QString::fromLocal8Bit (funcStr));
	QString fullMsg = QString ("%1| INFO at %2: %3\n").arg (
			_getTimeFullFormat (), funcStr, msg);
	_outputMessage (fullMsg);
}

void Logger::_warning (const char *funcStr, const QString &msg)
{
	QString funcQStr = (funcStr == NULL ? "Unknown" :
			QString::fromLocal8Bit (funcStr));
	QString fullMsg = QString ("%1| WARNING at %2: %3\n").arg (
			_getTimeFullFormat (), funcStr, msg);
	_outputMessage (fullMsg);
}

void Logger::_warning (const char *funcStr, const QString &msg,
		OOPException &e)
{
	QString funcQStr = (funcStr == NULL ? "Unknown" :
			QString::fromLocal8Bit (funcStr));
	QString fullMsg = QString ("%1| WARNING at %2: %3. \n"
			"Related exception is %4.\n").arg (
			_getTimeFullFormat (), funcStr, msg, e.getDescription ());
	_outputMessage (fullMsg);
}

void Logger::_critical (const char *funcStr, const QString &msg)
{
	QString funcQStr = (funcStr == NULL ? "Unknown" :
			QString::fromLocal8Bit (funcStr));
	QString fullMsg = QString ("%1| ERROR at %2: %3\n").arg (
			_getTimeFullFormat (), funcStr, msg);
	_outputMessage (fullMsg);
}

void Logger::_critical (const char *funcStr, const QString &msg,
		OOPException &e)
{
	QString funcQStr = (funcStr == NULL ? "Unknown" :
			QString::fromLocal8Bit (funcStr));
	QString fullMsg = QString ("%1| ERROR at %2: %3. \n"
			"Related exception is %4.\n").arg (
			_getTimeFullFormat (), funcStr, msg, e.getDescription ());
	_outputMessage (fullMsg);
}

void Logger::_outputMessage (const QString &msg)
{
	QString msgWithThread = QString ("[Thread %1]%2")
			.arg (GetCurrentThreadId ()).arg (msg);
	std::string msgStdStr = msgWithThread.toStdString ();
	if (_mode & FILE_OUT)
		_outLogStream << msgStdStr;
	if (_mode & STD_OUT)
		std::cout << msgWithThread.toLocal8Bit ().data ();
	if (_mode & DEBUG_OUT)
		OutputDebugStringA (msgStdStr.c_str ());
}